(* Copyright 2007 dnAnalytics Project.
 *
 * Contributors to this file:
 * Jurgen Van Gael
 *
 * This file is part of dnAnalytics.  dnAnalytics is licensed under the 
 * Microsoft Public License. See License.txt for a complete copy of the
 * license.
 *)
#light

namespace dnAnalytics.LinearAlgebra

open dnAnalytics.LinearAlgebra

/// A module which implements functional vector operations.
module Vector =
        
    /// Transform a vector into an array.
    let to_array (v: #Vector) =
        let n = v.Count
        Array.init n (fun i -> v.Item(i))
        
    /// Transform a vector into an array.
    let to_list (v: #Vector) =
        let n = v.Count
        List.init n (fun i -> v.Item(i))

    /// In-place mutation by applying a function to every element of the vector.
    let inplace_map (f: float -> float) (v: #Vector) =
        for i=0 to v.Count-1 do
            v.Item(i) <- f (v.Item(i))
        ()

    /// In-place mutation by applying a function to every element of the vector.
    let inplace_mapi (f: int -> float -> float) (v: #Vector) =
        for i=0 to v.Count-1 do
            v.Item(i) <- f i (v.Item(i))
        ()
        
    /// In-place scaling of vector components.
    let inplace_scale (f: float) (v: #Vector) =
        for i=0 to v.Count-1 do
            v.Item(i) <- f * v.Item(i)
        ()
    
    /// In-place assignment.
    let inplace_assign (f: int -> float) (v: #Vector) =
        for i=0 to v.Count-1 do
            v.Item(i) <- f i
        ()
        
    /// In-place vector addition.
    let inplace_add (v: #Vector) (w: #Vector) =
        v.Add w
        
    /// In place vector subtraction.
    let inplace_sub (v: #Vector) (w: #Vector) =
        v.Subtract w
    
    /// Functional map operator for vectors.
    /// <include file='../../../../FSharpExamples/DenseVector.xml' path='example'/> 
    let map f (v: #Vector) =
        let w = v.Clone()
        inplace_mapi (fun _ x -> f x) w
        w
        
    /// Applies a function to all elements of the vector.
    let iter (f: float -> unit) (v: #Vector) =
        for i=0 to v.Count-1 do
            f (v.Item i)
        
    /// Applies a function to all elements of the vector.
    let iteri (f: int -> float -> unit) (v: #Vector) =
        for i=0 to v.Count-1 do
            f i (v.Item i)
            
    /// Maps a vector to a new vector by applying a function to every element.
    let mapi (f: int -> float -> float) (v: #Vector) =
        let w = v.Clone()
        inplace_mapi f w
        w

    /// Fold all entries of a vector.
    let fold (f: 'a -> float -> 'a) (acc0: 'a) (v: #Vector) =
        let mutable acc = acc0
        for i=0 to v.Count-1 do
            acc <- f acc (v.Item(i))
        acc

    /// Fold all entries of a vector using a position dependent folding function.
    let foldi (f: int -> 'a -> float -> 'a) (acc0: 'a) (v: #Vector) =
        let mutable acc = acc0
        for i=0 to v.Count-1 do
            acc <- f i acc (v.Item(i))
        acc
        
    /// Checks whether a predicate is satisfied for every element in the vector.
    let forall (p: float -> bool) (v: #Vector) =
        let mutable b = true
        let mutable i = 0
        while b && i < v.Count do
            b <- b && (p (v.Item(i)))
            i <- i+1
        b
    
    /// Checks whether there is an entry in the vector that satisfies a given predicate.
    let exists (p: float -> bool) (v: #Vector) =
        let mutable b = false
        let mutable i = 0
        while not(b) && i < v.Count do
            b <- b || (p (v.Item(i)))
            i <- i+1
        b
    
    /// Checks whether a predicate is true for all entries in a vector.
    let foralli (p: int -> float -> bool) (v: #Vector) =
        let mutable b = true
        let mutable i = 0
        while b && i < v.Count do
            b <- b && (p i (v.Item(i)))
            i <- i+1
        b
    
    /// Checks whether there is an entry in the vector that satisfies a given position dependent predicate.
    let existsi (p: int -> float -> bool) (v: #Vector) =
        let mutable b = false
        let mutable i = 0
        while not(b) && i < v.Count do
            b <- b || (p i (v.Item(i)))
            i <- i+1
        b

    /// Scans a vector; like fold but returns the intermediate result.
    let scan_left (f: float -> float -> float) (v: #Vector) =
        let w = v.Clone()
        let mutable p = v.Item(0)
        for i=1 to v.Count-1 do
            p <- f p (v.Item(i))
            w.[i] <- p
        w

    /// Scans a vector; like fold but returns the intermediate result.
    let scan_right (f: float -> float -> float) (v: #Vector) =
        let w = v.Clone()
        let mutable p = v.Item(v.Count-1)
        for i=2 to v.Count do
            p <- f (v.Item(v.Count - i)) p
            w.[v.Count - i] <- p
        w

    /// Reduces a vector: the result of this function will be f(...f(f(v[0],v[1]), v[2]),..., v[n]).
    let reduce_left (f: float -> float -> float) (v: #Vector) =
        let mutable p = v.Item(0)
        for i=1 to v.Count-1 do
            p <- f p (v.Item(i))
        p

    /// Reduces a vector: the result of this function will be f(v[1], ..., f(v[n-2], f(v[n-1],v[n]))...).
    let reduce_right (f: float -> float -> float) (v: #Vector) =
        let mutable p = v.Item(v.Count-1)
        for i=2 to v.Count do
            p <- f (v.Item(v.Count - i)) p
        p